Шаг 7 - Обработка событий

Загрузить проект

Механизм обработки событий в Java весьма прост, достаточно мощный и очень гибкий. Не верите? Судите сами:

Немного теории

Чтобы обработать событие от компонента ему (компоненту) надо указать объект который будет этим заниматься. Например, для обработки управляющего (action) события это выглядит следующим образом:
AnyComponent.addActionListener(ObWhoMustHandleEvents);
Одному компоненту можно назначить, таким образом, несколько обработчиков событий. Каким же свойством должен объект, который сможет обработать событие (в нашем примере ObWhoMustHandleEvent)? Все очень просто - он должен имплементировать интерфейс ActionListener. В интерфейсе всего один метод: actionPerformed(ActionEvent e), который и нужно реализовать вашему объекту - обработчику события. Этот метод выполнится при возникновении события.

По аналогичной схеме обрабатываются и другие события. Например, чтоб обработать события от мыши, указываем функцией addMouseListener(ObWhoMustHandleEvents) объект, который будет их обрабатывать, этот объект должен имплементировать интерфейс MouseListener. Здесь нужно реализировать уже 5 функций mousePressed(MouseEvent e), mouseReleased(MouseEvent e), mouseEntered(MouseEvent e), mouseExited(MouseEvent e) и mouseClicked(MouseEvent e). И так далее. Вот функции которыми обладают все компоненты для регистрации обработчиков событий:

Кроме того, разные компоненты могут иметь свои специфические события и соответственно имеют функции для назначения обработчиков этих событий. Например, для событий окон, таких как открытие, закрытие активизация окна и т.д., окна регистрируют обработчика событий (который имплементирует интерфейс WindowListener) функцией addWindowListener(ObWhoMustHandleEvents). Например хотим мы обработать событие активизации главного окна приложения. Сделать это можно так:
public class MainWindow extends JFrame implements WindowListener 
{
//...........
 //скажем объекту окна пусть сам свои событыя и обрабатывает
 addWindowListener(this);

 //реализируем методы интерфейса WindowListener
 public void windowActivated(WindowEvent e) 
 {
   doSomething();
 }
 public void windowClosing(WindowEvent e) {}
 public void windowClosed(WindowEvent e) {}
 public void windowOpened(WindowEvent e) {}
 public void windowIconified(WindowEvent e) {}
 public void windowDeiconified(WindowEvent e) {}
 public void windowDeactivated(WindowEvent e) {}
//...........
}
Чтоб обработать событие активации в функции windowActivated(WindowEvent e) нам пришлось еще 6 пустых функций вписать ибо раз взялись имплементировать интерфейс то надо сделать это полностью, иначе класс свой абстрактным сделаем. Чтоб не вписывать пустые функции придуманы классы-адаптеры которые имплементируют соответствующие интерфейсы и содержат реализацию их методов по умолчанию. Например, для событий окна существует WindowAdapter, для событий мыши - MouseAdapter. Ваш класс обрабатывающий событие может унаследовать такой класс-адаптер и перегрузить нужный Вам метод для обработки конкретного события. Но как это использовать в примере выше? Ведь наш класс уже наследуется от JFrame а многократного наследования в Java нету! Выход простой - создадим специальный внутренний класс - обработчик событий окна (внутренний лучше потому что он будет иметь доступ к всем полям содержащего его класса). Пример:
public class MainWindow extends JFrame
{
 //...........
   //Действие 1
   //скажем объекту окна что обрабатывать
   //его события будет класс OurListener
   //создавая его сходу
  addWindowListener(new OurListener());

   //Действие 2
   //реализируем внутренний класс OurListener
  class OurListener extends WindowAdapter
  {
     //перегружаем нужный нам метод
   public void windowActivated(WindowEvent e) 
   {
    doSomething();
   }
  }
 //...........
}
А теперь оба окурка давим одновременно:) - перепишем этот код объединив действия 1 и 2 в одно:
public class MainWindow extends JFrame
{
 //...........
   
   //скажем объекту окна что обрабатывать
   //его события будет класс Х!
   //создадим его сходу с помощью 
   //конструктора родительского класса
   //и тут же перегрузим нужный нам метод!
  addWindowListener(new WindowAdapter()
  {
   public void windowActivated(WindowEvent e) 
   {
    doSomething();
   }
  });

 //...........
}
Ну как вам аргументец функции addWindowListener? Какое у этого класса название? Нету у него имени (да и незачем в принципе оно ему), он является потомком класса WindowAdapter один из методов которого мы перегрузили, большего нам от него и не надобно.

Осталось нам разобраться что за аргументы передаются в функции-обработчики событий. Как видим, они разные: в случае с событием типа action в функции actionPerformed аргументом есть объект типа ActionEvent, в функциях событий окна - аргументом есть WindowEvent, для обработчиков событий мыши аргументом будет MouseEvent. Как Вы уже догадались это все одного поля ягоды. Они все содержат информацию о соответствующем событии. Их предком является класс EventObject. С помощью метода getSource, которым обеспечивает данный класс своих потомков, Вы можете получить объект создавший событие. Кроме того у каждого из вышеперечисленных классов можно узнать специфические детали для каждого события, например у объекта MouseEvent можно узнать координаты мыши во время возникновения события, количество кликов, какой кнопкой кликали и т.д.

Создаем код

В нижеприведенном примере напишем апплет. Разместим на него кнопку и две текстовые области. В одну из них будем записывать текст при нажатии кнопки, а во вторую при возникновении таких событий мыши как ее вход и выход в область территории апплета и клик по этой территории.

import java.awt.*;
import javax.swing.*;
  //нижеследующее импортируем для работы с событиями
import java.awt.event.*;

public class EventApplet extends JApplet implements ActionListener 
{
 JButton button;
 JTextArea ButtArea, MouseArea;

 public void init()
 {

  Container contPane = getContentPane();
  contPane.setLayout(new BoxLayout(contPane, BoxLayout.Y_AXIS));
  
  button=new JButton("Our Button");
  button.addActionListener(this); 
  
  ButtArea=new JTextArea(10,10);
    //поместим наши JTextArea на панель которая
    //может создать скроллинг
  JScrollPane ScrollPane_butt = new JScrollPane(ButtArea);
    //окружим эту панель рамкой с заголовком
  ScrollPane_butt.setBorder(BorderFactory.createTitledBorder("Button actions:"));

    //тут аналогично...
  MouseArea=new JTextArea(10,10);
  JScrollPane ScrollPane_mouse = new JScrollPane(MouseArea);
  ScrollPane_mouse.setBorder(BorderFactory.createTitledBorder("Mouse actions:"));

    //поместим нашу кнопку и JScrollPane панели 
    //которые содержат в себе наши JTextArea
    //на главную панель апплета
  contPane.add(button);
  contPane.add(ScrollPane_butt);
  contPane.add(ScrollPane_mouse);

    //назначим територии апплета обработчик событий
    //мыши создав его на ходу
  addMouseListener(new MouseAdapter(){
  
  public void mouseClicked(MouseEvent e) 
  {
    MouseArea.append("Mouse clicked"+e.getClickCount()+"times"+"\n");
  }

  public void mouseEntered(MouseEvent e) 
  {
    MouseArea.append("Mouse entered"+"\n");
  }

  public void mouseExited(MouseEvent e) 
  {
    MouseArea.append("Mouse exited"+"\n");   
  }

  });

 }
  //обработаем нажатие кнопки 
 public void actionPerformed(ActionEvent e) 
 {
   ButtArea.append("Button Clicked" + "\n");
 }
}
Компилируем, смотрим. У кого не получилось - грузите проект, там кроме апплета есть еще аналогичное приложение (EventApp). Кстати, Вы заметили что при компиляции кроме файла главного класса еще какой-то файл EventApplet$1.class получается? Это не спам! Это наш анонимный внутренний класс-обработчик событий мыши. Ну теперь можно покликать по кнопке, повходить-выходить на территорию панели апплета не занятую нашими компонентами (возле кнопки ее больше всего должно быть) и покликать по этой территории. Попробуйте сделать многократный клик и посмотрите на запись событий в нижней текстовой области. При переполнении текстовых областей должна прокрутка появляться - не даром же мы их на специальные панели ставили!
Автор: Vitaly
Hosted by uCoz